home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 April: Mac OS SDK / Dev.CD Apr 97 SDK1.toast / Development Kits (Disc 1) / Apple Game Sprockets / RAVE SDK 1.06 GM for MacOS / Example Projects / GameScene / GSGameScene.c < prev    next >
Encoding:
Text File  |  1996-03-18  |  41.3 KB  |  1,455 lines  |  [TEXT/ALFA]

  1. // ===========================================================================
  2. //
  3. //    GSGameScene.c
  4. //    
  5. //    Copyright (C) 1996 Apple Computer, Inc.  All rights reserved.
  6. //
  7. // ===========================================================================
  8.  
  9.  
  10. // ===========================================================================
  11. //    Includes
  12. // ===========================================================================
  13.  
  14. #include <stdlib.h>
  15. #include <stdio.h>
  16.  
  17. #include "RAVE.h"
  18.  
  19. #include "GSGameScene.h"
  20. #include "GSImage.h"
  21. #include "GSPicture.h"
  22. #include "GSColorTable.h"
  23. #include "GSDrawInfo.h"
  24. #include "GSUtilities.h"
  25. #include "GSError.h"
  26.  
  27.  
  28. // ===========================================================================
  29. //    Constants
  30. // ===========================================================================
  31.  
  32. #define                        kVendorID_Apple                    0
  33. #define                        kEngineID_AppleHardware            (-1)
  34.  
  35. #define                     kTextureTriCount                2
  36. #define                     kTextureTriGroupCount            10
  37.  
  38. #define                     kClipping_front                    0.0
  39. #define                     kClipping_back                    10.0
  40.  
  41. #define                     kBackgroundZ                    0.9
  42. #define                     kBackgroundInvW                    (1.0 / 20.0)
  43. #define                     kWallsZ_front                    0.1
  44. #define                     kWallsZ_back                    0.8
  45. #define                     kWallsZeye_front                1.0
  46. #define                     kWallsZeye_back                    6.0
  47. #define                     kWallsInvW_front                (1.0 / kWallsZeye_front)
  48. #define                     kWallsInvW_back                    (1.0 / kWallsZeye_back)
  49.  
  50. #define                     kBackground_U                    4.0
  51. #define                     kBackground_V                    4.0
  52. #define                     kWalls_U                        5.0
  53. #define                     kWalls_V                        1.0
  54. #define                     kBackWall_U                        1.0
  55. #define                     kBackWall_V                        1.0
  56. #define                     kFloor_U                        1.0
  57. #define                     kFloor_V                        5.0
  58.  
  59. #define                     kColumn_left                    0.25
  60. #define                     kColumn_right                    0.5
  61. #define                     kColumn_top                        -0.5
  62. #define                     kColumn_bottom                    0.5
  63. #define                     kColumnZ_front                    2.0
  64. #define                     kColumnZ_back                    2.25
  65.  
  66. #define                     kColumnFrontU_min                0.0
  67. #define                     kColumnFrontU_max                0.25
  68. #define                     kColumnFrontV_min                0.0
  69. #define                     kColumnFrontV_max                1.0
  70. #define                     kColumnSideU_min                0.5
  71. #define                     kColumnSideU_max                0.75
  72. #define                     kColumnSideV_min                0.0
  73. #define                     kColumnSideV_max                1.0
  74.  
  75. #define                     kBox1_left                        -0.5
  76. #define                     kBox1_right                        -0.1
  77. #define                     kBox1_top                        0.1
  78. #define                     kBox1_bottom                    0.5
  79. #define                     kBox1_front                        1.1
  80. #define                     kBox1_back                        1.9
  81. #define                     kBox1_triCount                    100
  82.  
  83. #define                     kTexture_background                0
  84. #define                     kTexture_leftWall                1
  85. #define                     kTexture_rightWall                2
  86. #define                     kTexture_backWall                3
  87. #define                     kTexture_floor                    4
  88. #define                     kTexture_column                    5
  89. #define                     kTexture_greenLava                6
  90. #define                     kTexture_redLava                7
  91. #define                     kTextureCount                    8
  92.  
  93. #define                     kGunZ                            0.001
  94. #define                     kIntestines_Zeye                3.5
  95. #define                     kIntestines_Yeye                0.5
  96. #define                     kBitmap_gun                        0
  97. #define                     kBitmap_intestines                1
  98. #define                     kBitmapCount                    2
  99.  
  100.  
  101. // ===========================================================================
  102. //    Types
  103. // ===========================================================================
  104.  
  105. typedef struct TGSTextureTri {
  106.     TQAVTexture                v1;
  107.     TQAVTexture                v2;
  108.     TQAVTexture                v3;
  109.     unsigned long            flags;
  110.     short                    texture;
  111. } TGSTextureTri;
  112.  
  113. typedef struct TGSTextureTriGroup {
  114.     TGSTextureTri                    tris[10];
  115.     struct TGSTextureTriGroup*        next;
  116. } TGSTextureTriGroup;
  117.  
  118. typedef struct TGSTextureTriList {
  119.     TGSTextureTriGroup*        head;
  120.     TGSTextureTriGroup*        tail;
  121.     unsigned char            triIndex;
  122. } TGSTextureTriList;
  123.  
  124.  
  125. // ===========================================================================
  126. //    Globals
  127. // ===========================================================================
  128.  
  129. TGSDrawInfo*                gDrawInfoP;
  130. float                        gWindowWidth;
  131. float                        gWindowHeight;
  132.  
  133. unsigned long                gTriFlags;
  134. TGSTextureTriList             gTextureTriList;
  135.  
  136. TQATexture*                    gTextures[kTextureCount];
  137. TGSImage*                    gTextureImages[kTextureCount];
  138. TQAColorTable*                gTextureColorTables[kTextureCount];
  139.  
  140. #if (kQAPlatform == kQAMacOS)
  141. char*                        gTextureFileNames[kTextureCount] = {
  142.                                 "GS_Stars.16.pict",
  143.                                 "GS_DarkBrownWall.16.pict",
  144.                                 "GS_GreenBrownOvalWall.16.pict",
  145.                                 "GS_ShipDoor.16.pict",
  146.                                 "GS_GreyFloor.16.pict",
  147.                                 "GS_YellowBlackStripes.16.pict",
  148.                                 "GS_GreenLava.16.pict",
  149.                                 "GS_RedLava.16.pict"
  150.                             };
  151. #endif
  152.                             
  153. TQABitmap*                    gBitmaps[kBitmapCount];
  154. TGSImage*                    gBitmapImages[kBitmapCount];
  155. TQAColorTable*                gBitmapColorTables[kBitmapCount];
  156.  
  157. #if (kQAPlatform == kQAMacOS)
  158. char*                        gBitmapFileNames[kBitmapCount] = {
  159.                                 "GS_AssaultRifle.cl8.pict",
  160.                                 "GS_Intestines.cl8.pict"
  161.                             };
  162. #endif
  163.  
  164.  
  165. // ===========================================================================
  166. //    Prototypes
  167. // ===========================================================================
  168.  
  169.     TGSError
  170. GSLoadTextures(
  171.     TGSDrawInfo*            inDrawInfo);
  172.  
  173.     void
  174. GSUnloadTextures(
  175.     TGSDrawInfo*            inDrawInfo);
  176.  
  177.     TGSError
  178. GSLoadBitmaps(
  179.     TGSDrawInfo*            inDrawInfo);
  180.  
  181.     void
  182. GSUnloadBitmaps(
  183.     TGSDrawInfo*            inDrawInfo);
  184.     
  185.     void 
  186. GSDrawBitmaps(
  187.     TGSDrawInfo*            inDrawInfo);
  188.  
  189.     void
  190. GSBoundedRandomVTexture(
  191.     TQAVTexture*            inVertex,
  192.     float                    inLeft,
  193.     float                    inRight,
  194.     float                    inTop,
  195.     float                    inBottom,
  196.     float                    inFront,
  197.     float                    inBack);
  198.  
  199.     void
  200. GSRandomRGBDefaultHighlight(
  201.     TQAVTexture*            inVertex);
  202.  
  203.     float
  204. GSGetScreenX(
  205.     float                    inX,
  206.     float                    inZ);
  207.  
  208.     float
  209. GSGetScreenY(
  210.     float                    inY,
  211.     float                    inZ);
  212.  
  213.     float
  214. GSGetScreenZ(
  215.     float                    inZ);
  216.  
  217.     void
  218. GSStoreBackground(
  219.     float                     inWidth,
  220.     float                     inHeight,
  221.     float                     inDepth);
  222. void GSStoreColumn();
  223.  
  224.     void
  225. GSStoreWalls(
  226.     float                     inBackWidth,
  227.     float                     inBackHeight,
  228.     float                     inFrontZ,
  229.     float                     inBackZ);
  230.     
  231.     void 
  232. GSStoreRandomTris(void);
  233.  
  234.     Boolean
  235. GSTextureTriList_New(
  236.     TGSTextureTriList*        inTextureTriList);
  237.  
  238.     void
  239. GSTextureTriList_Delete(
  240.     TGSTextureTriList*        inTextureTriList);
  241.  
  242.     Boolean
  243. GSTextureTriList_IsValid(
  244.     TGSTextureTriList*        inTextureTriList);
  245.  
  246.     Boolean
  247. GSTextureTriList_NewTextureTriGroup(
  248.     TGSTextureTriList*        inTextureTriList);
  249.  
  250.     Boolean
  251. GSTextureTriList_StoreTri(
  252.     TGSTextureTriList*        inTextureTriList,
  253.     TQAVTexture*            inVert1,
  254.     TQAVTexture*            inVert2,
  255.     TQAVTexture*            inVert3,
  256.     unsigned long            inFlags,
  257.     short                    inTexture);
  258.  
  259.     Boolean
  260. GSTextureTriList_StoreQuad(
  261.     TGSTextureTriList*        inTextureTriList,
  262.     TQAVTexture*            inVert1,
  263.     TQAVTexture*            inVert2,
  264.     TQAVTexture*            inVert3,
  265.     TQAVTexture*            inVert4,
  266.     unsigned long            inFlags,
  267.     short                    inTexture);
  268.  
  269.     void
  270. GSTextureTriList_Draw(
  271.     TGSTextureTriList*        inTextureTriList,
  272.     TGSDrawInfo*            inDrawInfo);
  273.  
  274.  
  275. // ===========================================================================
  276. //    GSTestGameScene
  277. // ===========================================================================
  278.     TGSError 
  279. GSDrawGameScene(
  280.     TGSDrawInfo*            inDrawInfo)
  281. {
  282.     char                    drawBitmapsFlagString[4] = "";
  283.     TGSError                gsError = kGSError_None;
  284.     
  285.     if (GSTextureTriList_New(&gTextureTriList) == false) {
  286.             // there's not enough memory to store the tris, so we can't
  287.             // run the test
  288.         return kGSError_NotEnoughMemory;
  289.     }
  290.         
  291.     gDrawInfoP = inDrawInfo;
  292.     
  293.         // all the triangles are front-facing, so use "none"
  294.         // for the flags parameter
  295.     gTriFlags = kQATriFlags_None;
  296.     
  297.         // set up the window size globals
  298.     gWindowWidth = inDrawInfo->mContextRect.right - inDrawInfo->mContextRect.left;
  299.     gWindowHeight = inDrawInfo->mContextRect.bottom - inDrawInfo->mContextRect.top;
  300.  
  301.     gsError = GSLoadTextures(inDrawInfo);
  302.     
  303.     if (gsError != kGSError_None) {
  304.             // there was a problem while loading the textures, so don't do
  305.             // any drawing and skip right to the cleanup
  306.         goto cleanup;
  307.     }
  308.         
  309.     gsError = GSLoadBitmaps(inDrawInfo);
  310.     
  311.     if (gsError != kGSError_None) {
  312.             // there was a problem while loading the bitmaps, so don't do
  313.             // any drawing and skip right to the cleanup
  314.         goto cleanup;
  315.     }
  316.     
  317.     GSStoreBackground(gWindowWidth, gWindowHeight, kBackgroundZ);
  318.     
  319.     GSStoreWalls(
  320.         gWindowWidth * (1.0 / 6.0), gWindowHeight * (1.0 / 6.0), 
  321.         kWallsZ_front, kWallsZ_back);
  322.  
  323.     GSStoreColumn();
  324.     
  325.     GSStoreRandomTris();
  326.         
  327.     if (!GSTextureTriList_IsValid(&gTextureTriList)) {
  328.             // at some point we ran out of memory in which to store new
  329.             // tris, so we can't run the test
  330.         gsError = kGSError_NotEnoughMemory;
  331.         goto cleanup;
  332.     }
  333.     
  334.         // prepare to render into the draw context
  335.     QARenderStart(inDrawInfo->mContext, nil, nil);
  336.  
  337.         // render all the triangles we've stored in the tri list
  338.     GSTextureTriList_Draw(&gTextureTriList, inDrawInfo);
  339.  
  340.     GSDrawBitmaps(inDrawInfo);
  341.     
  342.         // let the engine know we've finished rendering
  343.     QARenderEnd(inDrawInfo->mContext, nil);
  344.     
  345.         // wait for the engine to catch up and finish drawing everything
  346.     QASync(inDrawInfo->mContext);
  347.         
  348. cleanup:
  349.     GSTextureTriList_Delete(&gTextureTriList);
  350.     GSUnloadTextures(inDrawInfo);
  351.     GSUnloadBitmaps(inDrawInfo);
  352.     
  353.     return gsError;
  354. }
  355.  
  356.  
  357. // ===========================================================================
  358. //    GSLoadTextures
  359. // ===========================================================================
  360.     TGSError
  361. GSLoadTextures(
  362.     TGSDrawInfo*            inDrawInfo)
  363. {
  364.     TGSPicture*                picture = nil;
  365.     TQAError                qaError = kQANoErr;
  366.     TGSError                gsError = kGSError_None;
  367.     TGSError                result = kGSError_None;
  368.     short                    i;
  369.  
  370.     for (i = 0; i < kTextureCount; i++) {
  371.             // read the picture data from the file in gTextureFileNames into a
  372.             // TGSPicture.  this object handles any necessary conversion from 
  373.             // the format of the picture data in the file to the RAVE texture 
  374.             // format. the disposal of this picture will be handled by the
  375.             // TGSImage we create below.
  376.         gsError = GSPicture_NewFromPath(&picture, inDrawInfo->mTextureFormat, 
  377.                 gTextureFileNames[i]);
  378.         
  379.         if (gsError != kGSError_None) {
  380.                 // we couldn't find the picture file, so record an error and
  381.                 // then try the next one
  382.             result = gsError;
  383.             
  384.             continue;
  385.         }
  386.             
  387.             // create a TGSImage from the TGSPicture we just created above.  
  388.             // this object fills in the TQAImage structure with the appropriate
  389.             // values from the TGSPicture.  it will also optionally make every
  390.             // black pixel in the picture transparent and create mip maps for
  391.             // the texture.  it handles the disposal of the TGSPicture.  we use
  392.             // the TGSImage below to create an actual RAVE texture.
  393.         gsError = GSImage_NewFromPicture(&gTextureImages[i], picture, 
  394.                 inDrawInfo->mTextureFormat, inDrawInfo->mTextureMakeBlackTransparent, 
  395.                 inDrawInfo->mTextureMakeMipMap);
  396.         
  397.         if (gsError != kGSError_None) {
  398.                 // for some reason we couldn't create a GSImage (probably
  399.                 // not enough memory), so break out of the loop.  we break instead 
  400.                 // of continuing since if there's not enough memory, there's no 
  401.                 // point going on.
  402.             result = gsError;
  403.             
  404.             break;
  405.         }
  406.         
  407.         if (inDrawInfo->mTextureMakeMipMap && !GSImage_IsValidMipMap(gTextureImages[i])) {
  408.                 // the texture is supposed to be mipmapped, but GSImage couldn't
  409.                 // mip map it for some reason
  410.             result = kGSError_RAVE;
  411.             
  412.             break;
  413.         }
  414.         
  415.             // try to create a texture for the engine, using the image data
  416.             // stored in the TGSImage in gTextureImages[i]
  417.         qaError = QATextureNew(inDrawInfo->mEngine, inDrawInfo->mTextureFlags,
  418.                 GSImage_GetPixelType(gTextureImages[i]), 
  419.                 GSImage_GetImages(gTextureImages[i]),
  420.                 &gTextures[i]);
  421.             
  422.         if (qaError != kQANoErr) {
  423.                 // for some reason the engine couldn't create a texture (probably
  424.                 // not enough memory), so break out of the loop.  we break 
  425.                 // instead of continuing since if there's not enough memory, 
  426.                 // there's no point going on.
  427.             result = kGSError_RAVE;
  428.             
  429.             break;
  430.         }
  431.         
  432.         if (inDrawInfo->mTextureFormat == kQAPixel_CL4 || 
  433.                 inDrawInfo->mTextureFormat == kQAPixel_CL8) {
  434.             TGSColorTable*            colorTableP = GSImage_GetColorTable(gTextureImages[i]);
  435.             GSAssert_(colorTableP);
  436.  
  437.                 // create a new color table in the engine from the color table
  438.                 // data in the TGSImage.  when a TGSPicture is created, it also
  439.                 // creates a TGSColorTable, if necessary, which in turn stores 
  440.                 // the color table from the picture file in an array of pixels
  441.                 // in TQAImagePixelType format.  we can get the TGSColorTable
  442.                 // out of the TGSImage by calling GSImage_GetColorTable.  
  443.                 // 
  444.                 // once the color table data has been used to create a 
  445.                 // TQAColorTable, we can delete it.  in this case, however, it 
  446.                 // won't be deleted until the TGSPicture which stores it is 
  447.                 // itself deleted.
  448.             qaError = QAColorTableNew(inDrawInfo->mEngine, 
  449.                     GSColorTable_GetType(colorTableP), 
  450.                     GSColorTable_GetData(colorTableP),
  451.                     inDrawInfo->mTextureUseTransparentIndex, 
  452.                     &gTextureColorTables[i]);
  453.                     
  454.             if (qaError != kQANoErr) {
  455.                     // we couldn't create a color table in this engine (perhaps
  456.                     // it doesn't support CL textures), so break out of the loop, 
  457.                     // since we can't continue if the engine can't create 
  458.                     // color tables.
  459.                 result = kGSError_RAVE;
  460.                 
  461.                 break;
  462.             }
  463.     
  464.                 // bind this color table to the texture.  
  465.             qaError = QATextureBindColorTable(inDrawInfo->mEngine,
  466.                     gTextures[i], gTextureColorTables[i]);
  467.             
  468.             if (qaError != kQANoErr) {
  469.                     // we couldn't bind this color table to the texture in 
  470.                     // this engine, so break out of the loop, since we won't 
  471.                     // be able to draw this texture
  472.                 result = kGSError_RAVE;
  473.                 
  474.                 break;
  475.             }
  476.         }
  477.             
  478.         if (inDrawInfo->mTextureDetach) {
  479.                 // try to detach the texture from the engine
  480.             qaError = QATextureDetach(inDrawInfo->mEngine, gTextures[i]);
  481.  
  482.                 // if the texture was successfully detached, delete the image
  483.                 // which stores the texture's pixmap, since the engine now
  484.                 // has its own copy of that data.  if the texture couldn't be
  485.                 // detached, don't do anything (i.e., hold on to the image).
  486.             if (qaError == kQANoErr) {
  487.                 GSImage_Delete(gTextureImages[i]);
  488.                 gTextureImages[i] = nil;
  489.             }
  490.         }
  491.     } // endfor
  492.  
  493.     return result;
  494. }
  495.  
  496.  
  497. // ===========================================================================
  498. //    GSUnloadTextures
  499. // ===========================================================================
  500.     void
  501. GSUnloadTextures(
  502.     TGSDrawInfo*            inDrawInfo)
  503. {
  504.     short                    i;
  505.  
  506.     for (i = 0; i < kTextureCount; i++) {
  507.             // dispose of the textures
  508.         if (gTextures[i] != nil) {
  509.             QATextureDelete(inDrawInfo->mEngine, gTextures[i]);
  510.             gTextures[i] = nil;
  511.         }
  512.  
  513.             // dispose of the color tables
  514.         if (gTextureColorTables[i] != nil) {
  515.             QAColorTableDelete(inDrawInfo->mEngine, gTextureColorTables[i]);
  516.             gTextureColorTables[i] = nil;
  517.         }
  518.  
  519.             // dispose of the image which is referenced by the texture
  520.         if (gTextureImages[i] != nil) {
  521.             GSImage_Delete(gTextureImages[i]);
  522.             gTextureImages[i] = nil;
  523.         }
  524.     }
  525. }
  526.  
  527.  
  528. // ===========================================================================
  529. //    GSLoadBitmaps
  530. // ===========================================================================
  531.     TGSError
  532. GSLoadBitmaps(
  533.     TGSDrawInfo*            inDrawInfo)
  534. {
  535.     TGSPicture*                picture = nil;
  536.     TQAError                qaError = kQANoErr;
  537.     TGSError                gsError = kGSError_None;
  538.     TGSError                result = kGSError_None;
  539.     short                    i;
  540.     
  541.     for (i = 0; i < kBitmapCount; i++) {
  542.             // read the picture data from the file in gBitmapFileNames into a
  543.             // TGSPicture.  this object handles any necessary conversion from 
  544.             // the format of the picture data in the file to the RAVE bitmap 
  545.             // format. the disposal of this picture will be handled by the
  546.             // TGSImage we create below.
  547.         gsError = GSPicture_NewFromPath(&picture, inDrawInfo->mBitmapFormat, 
  548.                 gBitmapFileNames[i]);
  549.         
  550.         if (gsError != kGSError_None) {
  551.                 // we couldn't find the picture file, so record an error and
  552.                 // then try the next one
  553.             result = gsError;
  554.             
  555.             continue;
  556.         }
  557.     
  558.             // create a TGSImage from the TGSPicture we just created above.  
  559.             // this object fills in the TQAImage structure with the appropriate
  560.             // values from the TGSPicture.  it will also optionally make every
  561.             // black pixel in the picture transparent and create mip maps for
  562.             // the bitmap.  it handles the disposal of the TGSPicture.  we use
  563.             // the TGSImage below to create an actual RAVE bitmap.
  564.         gsError = GSImage_NewFromPicture(&gBitmapImages[i], picture, 
  565.                 inDrawInfo->mBitmapFormat, 
  566.                 inDrawInfo->mBitmapMakeBlackTransparent, false);
  567.         
  568.         if (gsError != kGSError_None) {
  569.                 // for some reason we couldn't create a GSImage (probably
  570.                 // not enough memory), so break out of the loop.  we break instead 
  571.                 // of continuing since if there's not enough memory, there's no 
  572.                 // point going on.
  573.             result = gsError;
  574.             
  575.             break;
  576.         }
  577.         
  578.             // try to create a bitmap for the engine, using the image data
  579.             // stored in the TGSImage in gBitmapImages[i]
  580.         qaError = QABitmapNew(inDrawInfo->mEngine, inDrawInfo->mBitmapFlags,
  581.                 GSImage_GetPixelType(gBitmapImages[i]), 
  582.                 GSImage_GetImages(gBitmapImages[i]),
  583.                 &gBitmaps[i]);
  584.             
  585.         if (qaError != kQANoErr) {
  586.                 // for some reason the engine couldn't create a bitmap (probably
  587.                 // not enough memory), so break out of the loop.  we break 
  588.                 // instead of continuing since if there's not enough memory, 
  589.                 // there's no point going on.
  590.             result = kGSError_RAVE;
  591.             
  592.             break;
  593.         }
  594.         
  595.         if (inDrawInfo->mBitmapFormat == kQAPixel_CL4 || 
  596.                 inDrawInfo->mBitmapFormat == kQAPixel_CL8) {
  597.             TGSColorTable*            colorTableP = GSImage_GetColorTable(gBitmapImages[i]);
  598.             GSAssert_(colorTableP);
  599.             
  600.                 // create a new color table in the engine from the color table
  601.                 // data in the TGSImage.  when a TGSPicture is created, it also
  602.                 // creates a TGSColorTable, if necessary, which in turn stores 
  603.                 // the color table from the picture file in an array of pixels
  604.                 // in TQAImagePixelType format.  we can get the TGSColorTable
  605.                 // out of the TGSImage by calling GSImage_GetColorTable.  
  606.                 // 
  607.                 // once the color table data has been used to create a 
  608.                 // TQAColorTable, we can delete it.  in this case, however, it 
  609.                 // won't be deleted until the TGSPicture which stores it is 
  610.                 // itself deleted.
  611.             qaError = QAColorTableNew(inDrawInfo->mEngine, 
  612.                     GSColorTable_GetType(colorTableP), 
  613.                     GSColorTable_GetData(colorTableP),
  614.                     inDrawInfo->mBitmapUseTransparentIndex, 
  615.                     &gBitmapColorTables[i]);
  616.                     
  617.             if (qaError != kQANoErr) {
  618.                     // we couldn't create a color table in this engine (perhaps
  619.                     // it doesn't support CL bitmaps), so break out of the loop, 
  620.                     // since we can't continue if the engine can't create 
  621.                     // color tables.
  622.                 result = kGSError_RAVE;
  623.                 
  624.                 break;
  625.             }
  626.     
  627.                 // bind this color table to the bitmap
  628.             qaError = QABitmapBindColorTable(inDrawInfo->mEngine,
  629.                     gBitmaps[i], gBitmapColorTables[i]);
  630.             
  631.             if (qaError != kQANoErr) {
  632.                     // we couldn't bind this color table to the bitmap in 
  633.                     // this engine, so break out of the loop, since we won't 
  634.                     // be able to draw this bitmap
  635.                 result = kGSError_RAVE;
  636.                 
  637.                 break;
  638.             }
  639.         }
  640.         
  641.         if (inDrawInfo->mBitmapDetach) {
  642.                 // try to detach the bitmap from the engine
  643.             qaError = QABitmapDetach(inDrawInfo->mEngine, gBitmaps[i]);
  644.  
  645.                 // if the bitmap was successfully detached, delete the image
  646.                 // which stores the bitmap's pixmap, since the engine now
  647.                 // has its own copy of that data.  if the bitmap couldn't be
  648.                 // detached, don't do anything (i.e., hold on to the image).
  649.             if (qaError == kQANoErr) {
  650.                 GSImage_Delete(gBitmapImages[i]);
  651.                 gBitmapImages[i] = nil;
  652.             }
  653.         }
  654.     } // endfor
  655.  
  656.     return result;
  657. }
  658.  
  659.  
  660. // ===========================================================================
  661. //    GSUnloadBitmaps
  662. // ===========================================================================
  663.     void
  664. GSUnloadBitmaps(
  665.     TGSDrawInfo*            inDrawInfo)
  666. {
  667.     short                    i;
  668.  
  669.     for (i = 0; i < kBitmapCount; i++) {
  670.             // dispose of the bitmaps
  671.         if (gBitmaps[i] != nil) {
  672.             QABitmapDelete(inDrawInfo->mEngine, gBitmaps[i]);
  673.             gBitmaps[i] = nil;
  674.         }
  675.  
  676.             // dispose of the color tables
  677.         if (gBitmapColorTables[i] != nil) {
  678.             QAColorTableDelete(inDrawInfo->mEngine, gBitmapColorTables[i]);
  679.             gBitmapColorTables[i] = nil;
  680.         }
  681.  
  682.             // dispose of the image which is referenced by the bitmap
  683.         if (gBitmapImages[i] != nil) {
  684.             GSImage_Delete(gBitmapImages[i]);
  685.             gBitmapImages[i] = nil;
  686.         }
  687.     }
  688. }
  689.  
  690.  
  691. // ===========================================================================
  692. //    GSDrawBitmaps
  693. // ===========================================================================
  694.     void 
  695. GSDrawBitmaps(
  696.     TGSDrawInfo*            inDrawInfo)
  697. {
  698.         // eyeZ / eyeZrange == screenZ / screenZrange
  699.         // solve for screenZ to get a Z value between 0 and 1 for intestines
  700.     float                    eyeZrange = kWallsZeye_back - kWallsZeye_front;
  701.     float                    screenZrange = kWallsZ_back - kWallsZ_front;
  702.     float                    intestinesZ = (kIntestines_Zeye / eyeZrange) * screenZrange;
  703.     TQAVGouraud                v;
  704.     
  705.         // set the color and alpha to white
  706.     v.r = v.g = v.b = v.a = 1.0;
  707.     
  708.         // center the gun bitmap horizontally and place it at the bottom of
  709.         // the window
  710.     v.x = (gWindowWidth - GSImage_GetWidth(gBitmapImages[kBitmap_gun])) / 2.0;
  711.     v.y = gWindowHeight - GSImage_GetHeight(gBitmapImages[kBitmap_gun]);
  712.     v.z = kGunZ;
  713.     v.invW = 1.0 / kGunZ;
  714.     
  715.         // draw the assault rifle bitmap
  716.     QADrawBitmap(inDrawInfo->mContext, &v, gBitmaps[kBitmap_gun]);
  717.     
  718.         // center the intestines bitmap horizontally and place it so its 
  719.         // bottom touches the floor at its Zeye coord, which affects its
  720.         // vertical coord on the screen.
  721.     v.x = (gWindowWidth - GSImage_GetWidth(gBitmapImages[kBitmap_intestines])) / 2.0;
  722.     v.y = GSGetScreenY(kIntestines_Yeye, kIntestines_Zeye) - GSImage_GetHeight(gBitmapImages[kBitmap_intestines]);
  723.     v.z = intestinesZ;
  724.     v.invW = 1.0 / intestinesZ;
  725.     
  726.         // draw the bitmap in both contexts
  727.     QADrawBitmap(inDrawInfo->mContext, &v, gBitmaps[kBitmap_intestines]);
  728. }
  729.  
  730.  
  731. // ===========================================================================
  732. //    GSGetScreenX
  733. // ===========================================================================
  734.     float 
  735. GSGetScreenX(
  736.     float                    inX,
  737.     float                    inZ)
  738. {
  739.     return (gWindowWidth * (0.5 + (inX / inZ)));
  740. }
  741.  
  742.  
  743. // ===========================================================================
  744. //    GSGetScreenY
  745. // ===========================================================================
  746.     float 
  747. GSGetScreenY(
  748.     float                    inY,
  749.     float                    inZ)
  750. {
  751.         // because screen Y values diminish towards the top of the screen,
  752.         // eye Y (inY) values are assumed to be positive towards the bottom 
  753.         // of the screen and negative towards the top.
  754.     return (gWindowHeight * (0.5 + (inY / inZ)));
  755. }
  756.  
  757.  
  758. // ===========================================================================
  759. //    GSGetScreenZ
  760. // ===========================================================================
  761.     float 
  762. GSGetScreenZ(
  763.     float                    inZ)
  764. {    
  765.         // inZ is assumed to be less than kClipping_back.  this maps the
  766.         // the eye-space Z to a value between 0 and 1
  767.     return (inZ / kClipping_back);
  768. }
  769.  
  770.  
  771. // ===========================================================================
  772. //    GSBoundedRandomVTexture
  773. // ===========================================================================
  774.     void 
  775. GSBoundedRandomVTexture(
  776.     TQAVTexture*            inVertex,
  777.     float                    inLeft,
  778.     float                    inRight,
  779.     float                    inTop,
  780.     float                    inBottom,
  781.     float                    inFront,
  782.     float                    inBack)
  783. {
  784.     float                    rangeX = inRight - inLeft;
  785.     float                    rangeY = inBottom - inTop;
  786.     float                    rangeZ = inBack - inFront;
  787.     
  788.         // first random values in eye space
  789.     inVertex->x = inLeft + rangeX * GSRandomFloat();
  790.     inVertex->y = inTop + rangeY * GSRandomFloat();
  791.     inVertex->z = inFront + rangeZ * GSRandomFloat();
  792.     
  793.         // invert the eye-space Z coord to get invW
  794.     inVertex->invW = 1.0 / inVertex->z;
  795.     
  796.         // now convert these to screen space
  797.     inVertex->x = GSGetScreenX(inVertex->x, inVertex->z);
  798.     inVertex->y = GSGetScreenY(inVertex->y, inVertex->z);
  799.     inVertex->z = GSGetScreenZ(inVertex->z);
  800.     
  801.         // make random U and V between 0 and 2
  802.     inVertex->uOverW = 2.0 * GSRandomFloat() * inVertex->invW;
  803.     inVertex->vOverW = 2.0 * GSRandomFloat() * inVertex->invW;
  804.     
  805.         // get random RGB values
  806.     inVertex->a = 1.0;
  807.     inVertex->r = GSRandomFloat();
  808.     inVertex->g = GSRandomFloat();
  809.     inVertex->b = GSRandomFloat();
  810.     
  811.     inVertex->kd_r = 1.0;
  812.     inVertex->kd_g = 1.0;
  813.     inVertex->kd_b = 1.0;
  814.     
  815.     inVertex->ks_r = 0.0;
  816.     inVertex->ks_g = 0.0;
  817.     inVertex->ks_b = 0.0;
  818. }
  819.  
  820.  
  821. // ===========================================================================
  822. //    GSRandomRGBDefaultHighlight
  823. // ===========================================================================
  824.     void 
  825. GSRandomRGBDefaultHighlight(
  826.     TQAVTexture*            inVertex)
  827. {
  828.         // make the vertex's RGB values random
  829.     inVertex->r = GSRandomFloat();
  830.     inVertex->g = GSRandomFloat();
  831.     inVertex->b = GSRandomFloat();
  832.  
  833.         // make the alpha and highlight values "default"
  834.     inVertex->a = 1.0;
  835.     
  836.     inVertex->kd_r = 1.0;
  837.     inVertex->kd_g = 1.0;
  838.     inVertex->kd_b = 1.0;
  839.     
  840.     inVertex->ks_r = 0.0;
  841.     inVertex->ks_g = 0.0;
  842.     inVertex->ks_b = 0.0;
  843. }
  844.  
  845.  
  846. // ===========================================================================
  847. //    GSStoreBackground
  848. // ===========================================================================
  849.     void 
  850. GSStoreBackground(
  851.     float                     inWidth,
  852.     float                     inHeight,
  853.     float                     inDepth)
  854. {
  855.     TQAVTexture                verts[4];
  856.  
  857.         // we subtract a little bit from the width and height values so that 
  858.         // they're fully inside the screen pixels
  859.     inWidth -= 0.1;
  860.     inHeight -= 0.1;
  861.     
  862.         // the background tris all have the same depth and invW
  863.     verts[0].z = verts[1].z = verts[2].z = verts[3].z = inDepth;
  864.     verts[0].invW = verts[1].invW = verts[2].invW = verts[3].invW = kBackgroundInvW;
  865.  
  866.         // all tri vertices will have random RGB values, default highlight
  867.     GSRandomRGBDefaultHighlight(&verts[0]);
  868.     GSRandomRGBDefaultHighlight(&verts[1]);
  869.     GSRandomRGBDefaultHighlight(&verts[2]);
  870.     GSRandomRGBDefaultHighlight(&verts[3]);
  871.  
  872.     verts[0].x = 0.0;
  873.     verts[0].y = 0.0;
  874.     verts[0].uOverW = 0.0;
  875.     verts[0].vOverW = kBackground_V * verts[0].invW;
  876.         
  877.     verts[1].x = 0.0;
  878.     verts[1].y = inHeight;
  879.     verts[1].uOverW = 0.0;
  880.     verts[1].vOverW = 0.0;
  881.         
  882.     verts[2].x = inWidth;
  883.     verts[2].y = inHeight;
  884.     verts[2].uOverW = kBackground_U * verts[2].invW;
  885.     verts[2].vOverW = 0.0;
  886.  
  887.     verts[3].x = inWidth;
  888.     verts[3].y = 0.0;
  889.     verts[3].uOverW = kBackground_U * verts[3].invW;
  890.     verts[3].vOverW = kBackground_V * verts[3].invW;
  891.  
  892.         // store the background rectangle
  893.     GSTextureTriList_StoreQuad(
  894.         &gTextureTriList, 
  895.         &verts[0], 
  896.         &verts[1], 
  897.         &verts[2], 
  898.         &verts[3], 
  899.         gTriFlags,
  900.         kTexture_background);
  901. }
  902.  
  903.  
  904. // ===========================================================================
  905. //    GSStoreColumn
  906. // ===========================================================================
  907.     void
  908. GSStoreColumn()
  909. {
  910.     TQAVTexture                verts[4];
  911.     
  912.         // eyeZ / eyeZrange == screenZ / screenZrange
  913.         // solve for screenZ to get a Z value between 0 and 1 for the front
  914.         // and side of the column
  915.     float                    eyeZrange = kWallsZeye_back - kWallsZeye_front;
  916.     float                    screenZrange = kWallsZ_back - kWallsZ_front;
  917.     float                    columnScreenZ_front = (kColumnZ_front / eyeZrange) * screenZrange;
  918.     float                    columnScreenZ_back = (kColumnZ_back / eyeZrange) * screenZrange;
  919.     
  920.         // all tri vertices will have random RGB values, default highlight
  921.     GSRandomRGBDefaultHighlight(&verts[0]);
  922.     GSRandomRGBDefaultHighlight(&verts[1]);
  923.     GSRandomRGBDefaultHighlight(&verts[2]);
  924.     GSRandomRGBDefaultHighlight(&verts[3]);
  925.  
  926.         // front of column
  927.     verts[0].x = GSGetScreenX(kColumn_left, kColumnZ_front);
  928.     verts[0].y = GSGetScreenY(kColumn_top, kColumnZ_front);
  929.     verts[0].z = columnScreenZ_front;
  930.     verts[0].invW = 1.0 / kColumnZ_front;
  931.     verts[0].uOverW = kColumnFrontU_min * verts[0].invW;
  932.     verts[0].vOverW = kColumnFrontV_max * verts[0].invW;
  933.         
  934.     verts[1].x = GSGetScreenX(kColumn_left, kColumnZ_front);
  935.     verts[1].y = GSGetScreenY(kColumn_bottom, kColumnZ_front);
  936.     verts[1].z = columnScreenZ_front;
  937.     verts[1].invW = 1.0 / kColumnZ_front;
  938.     verts[1].uOverW = kColumnFrontU_min * verts[1].invW;
  939.     verts[1].vOverW = kColumnFrontV_min * verts[1].invW;
  940.         
  941.     verts[2].x = GSGetScreenX(kColumn_right, kColumnZ_front);
  942.     verts[2].y = GSGetScreenY(kColumn_bottom, kColumnZ_front);
  943.     verts[2].z = columnScreenZ_front;
  944.     verts[2].invW = 1.0 / kColumnZ_front;
  945.     verts[2].uOverW = kColumnFrontU_max * verts[2].invW;
  946.     verts[2].vOverW = kColumnFrontV_min * verts[2].invW;
  947.         
  948.     verts[3].x = GSGetScreenX(kColumn_right, kColumnZ_front);
  949.     verts[3].y = GSGetScreenY(kColumn_top, kColumnZ_front);
  950.     verts[3].z = columnScreenZ_front;
  951.     verts[3].invW = 1.0 / kColumnZ_front;
  952.     verts[3].uOverW = kColumnFrontU_max * verts[3].invW;
  953.     verts[3].vOverW = kColumnFrontV_max * verts[3].invW;
  954.     
  955.     GSTextureTriList_StoreQuad(
  956.         &gTextureTriList, 
  957.         &verts[0], 
  958.         &verts[1], 
  959.         &verts[2], 
  960.         &verts[3], 
  961.         gTriFlags,
  962.         kTexture_column);
  963.  
  964.         // side of column
  965.     verts[0].x = GSGetScreenX(kColumn_left, kColumnZ_back);
  966.     verts[0].y = GSGetScreenY(kColumn_top, kColumnZ_back);
  967.     verts[0].z = columnScreenZ_back;
  968.     verts[0].invW = 1.0 / kColumnZ_back;
  969.     verts[0].uOverW = kColumnSideU_min * verts[0].invW;
  970.     verts[0].vOverW = kColumnSideV_max * verts[0].invW;
  971.         
  972.     verts[1].x = GSGetScreenX(kColumn_left, kColumnZ_back);
  973.     verts[1].y = GSGetScreenY(kColumn_bottom, kColumnZ_back);
  974.     verts[1].z = columnScreenZ_front;
  975.     verts[1].invW = 1.0 / kColumnZ_back;
  976.     verts[1].uOverW = kColumnSideU_min * verts[1].invW;
  977.     verts[1].vOverW = kColumnSideV_min * verts[1].invW;
  978.         
  979.     verts[2].x = GSGetScreenX(kColumn_left, kColumnZ_front);
  980.     verts[2].y = GSGetScreenY(kColumn_bottom, kColumnZ_front);
  981.     verts[2].z = columnScreenZ_front;
  982.     verts[2].invW = 1.0 / kColumnZ_front;
  983.     verts[2].uOverW = kColumnSideU_max * verts[2].invW;
  984.     verts[2].vOverW = kColumnSideV_min * verts[2].invW;
  985.         
  986.     verts[3].x = GSGetScreenX(kColumn_left, kColumnZ_front);
  987.     verts[3].y = GSGetScreenY(kColumn_top, kColumnZ_front);
  988.     verts[3].z = columnScreenZ_front;
  989.     verts[3].invW = 1.0 / kColumnZ_front;
  990.     verts[3].uOverW = kColumnSideU_max * verts[3].invW;
  991.     verts[3].vOverW = kColumnSideV_max * verts[3].invW;
  992.     
  993.     GSTextureTriList_StoreQuad(
  994.         &gTextureTriList, 
  995.         &verts[0], 
  996.         &verts[1], 
  997.         &verts[2], 
  998.         &verts[3], 
  999.         gTriFlags,
  1000.         kTexture_column);
  1001. }
  1002.  
  1003.  
  1004. // ===========================================================================
  1005. //    GSStoreWalls
  1006. // ===========================================================================
  1007.     void
  1008. GSStoreWalls(
  1009.     float                     inBackWidth,
  1010.     float                     inBackHeight,
  1011.     float                     inFrontZ,
  1012.     float                     inBackZ)
  1013. {
  1014.     float                    windowWidth = gWindowWidth - 0.1;
  1015.     float                    windowHeight = gWindowHeight - 0.1;
  1016.     float                    wallWidth = (windowWidth - inBackWidth) / 2.0;
  1017.     float                    floorDepth = (windowHeight - inBackHeight) / 2.0;
  1018.     float                    maxUV = 5.0;
  1019.     TQAVTexture                verts[4];
  1020.     
  1021.         // all tri vertices will have random RGB values, default highlight
  1022.     GSRandomRGBDefaultHighlight(&verts[0]);
  1023.     GSRandomRGBDefaultHighlight(&verts[1]);
  1024.     GSRandomRGBDefaultHighlight(&verts[2]);
  1025.     GSRandomRGBDefaultHighlight(&verts[3]);
  1026.  
  1027.         // the wall and floor u and v values go from 0 to maxUV, so uOverW 
  1028.         // and vOverW == maxUV * invW == 1 / W, and W == z
  1029.         
  1030.         // left wall
  1031.     verts[0].x = 0.0;
  1032.     verts[0].y = 0.0;
  1033.     verts[0].z = inFrontZ;
  1034.     verts[0].invW = kWallsInvW_front;
  1035.     verts[0].uOverW = 0.0;
  1036.     verts[0].vOverW = kWalls_V * verts[0].invW;
  1037.         
  1038.     verts[1].x = 0.0;
  1039.     verts[1].y = windowHeight;
  1040.     verts[1].z = inFrontZ;
  1041.     verts[1].invW = kWallsInvW_front;
  1042.     verts[1].uOverW = 0.0;
  1043.     verts[1].vOverW = 0.0;
  1044.         
  1045.     verts[2].x = wallWidth;
  1046.     verts[2].y = floorDepth + inBackHeight;
  1047.     verts[2].z = inBackZ;
  1048.     verts[2].invW = kWallsInvW_back;
  1049.     verts[2].uOverW = kWalls_U * verts[2].invW;
  1050.     verts[2].vOverW = 0.0;
  1051.         
  1052.     verts[3].x = wallWidth;
  1053.     verts[3].y = floorDepth;
  1054.     verts[3].z = inBackZ;
  1055.     verts[3].invW = kWallsInvW_back;
  1056.     verts[3].uOverW = kWalls_U * verts[3].invW;
  1057.     verts[3].vOverW = kWalls_V * verts[3].invW;
  1058.         
  1059.     GSTextureTriList_StoreQuad(
  1060.         &gTextureTriList, 
  1061.         &verts[0], 
  1062.         &verts[1], 
  1063.         &verts[2], 
  1064.         &verts[3], 
  1065.         gTriFlags,
  1066.         kTexture_leftWall);
  1067.         
  1068.         // back wall
  1069.     verts[0].x = wallWidth;
  1070.     verts[0].y = floorDepth;
  1071.     verts[0].z = inBackZ;
  1072.     verts[0].invW = kWallsInvW_back;
  1073.     verts[0].uOverW = 0.0;
  1074.     verts[0].vOverW = kBackWall_V * verts[0].invW;
  1075.         
  1076.     verts[1].x = wallWidth;
  1077.     verts[1].y = floorDepth + inBackHeight;
  1078.     verts[1].z = inBackZ;
  1079.     verts[1].invW = kWallsInvW_back;
  1080.     verts[1].uOverW = 0.0;
  1081.     verts[1].vOverW = 0.0;
  1082.         
  1083.     verts[2].x = wallWidth + inBackWidth;
  1084.     verts[2].y = floorDepth + inBackHeight;
  1085.     verts[2].z = inBackZ;
  1086.     verts[2].invW = kWallsInvW_back;
  1087.     verts[2].uOverW = kBackWall_U * verts[2].invW;
  1088.     verts[2].vOverW = 0.0;
  1089.         
  1090.     verts[3].x = wallWidth + inBackWidth;
  1091.     verts[3].y = floorDepth;
  1092.     verts[3].z = inBackZ;
  1093.     verts[3].invW = kWallsInvW_back;
  1094.     verts[3].uOverW = kBackWall_U * verts[3].invW;
  1095.     verts[3].vOverW = kBackWall_V * verts[3].invW;
  1096.         
  1097.     GSTextureTriList_StoreQuad(
  1098.         &gTextureTriList, 
  1099.         &verts[0], 
  1100.         &verts[1], 
  1101.         &verts[2], 
  1102.         &verts[3], 
  1103.         gTriFlags,
  1104.         kTexture_backWall);
  1105.         
  1106.         // right wall
  1107.     verts[0].x = wallWidth + inBackWidth;
  1108.     verts[0].y = floorDepth;
  1109.     verts[0].z = inBackZ;
  1110.     verts[0].invW = kWallsInvW_back;
  1111.     verts[0].uOverW = 0.0;
  1112.     verts[0].vOverW = kWalls_V * verts[0].invW;
  1113.         
  1114.     verts[1].x = wallWidth + inBackWidth;
  1115.     verts[1].y = floorDepth + inBackHeight;
  1116.     verts[1].z = inBackZ;
  1117.     verts[1].invW = kWallsInvW_back;
  1118.     verts[1].uOverW = 0.0;
  1119.     verts[1].vOverW = 0.0;
  1120.         
  1121.     verts[2].x = windowWidth;
  1122.     verts[2].y = windowHeight;
  1123.     verts[2].z = inFrontZ;
  1124.     verts[2].invW = kWallsInvW_front;
  1125.     verts[2].uOverW = kWalls_U * verts[2].invW;
  1126.     verts[2].vOverW = 0.0;
  1127.         
  1128.     verts[3].x = windowWidth;
  1129.     verts[3].y = 0.0;
  1130.     verts[3].z = inFrontZ;
  1131.     verts[3].invW = kWallsInvW_front;
  1132.     verts[3].uOverW = kWalls_U * verts[3].invW;
  1133.     verts[3].vOverW = kWalls_V * verts[3].invW;
  1134.         
  1135.     GSTextureTriList_StoreQuad(
  1136.         &gTextureTriList, 
  1137.         &verts[3], 
  1138.         &verts[2], 
  1139.         &verts[1], 
  1140.         &verts[0], 
  1141.         gTriFlags,
  1142.         kTexture_rightWall);
  1143.         
  1144.         // floor
  1145.     verts[0].x = wallWidth;
  1146.     verts[0].y = floorDepth + inBackHeight;
  1147.     verts[0].z = inBackZ;
  1148.     verts[0].invW = kWallsInvW_back;
  1149.     verts[0].uOverW = 0.0;
  1150.     verts[0].vOverW = kFloor_V * verts[0].invW;
  1151.         
  1152.     verts[1].x = 0.0;
  1153.     verts[1].y = windowHeight;
  1154.     verts[1].z = inFrontZ;
  1155.     verts[1].invW = kWallsInvW_front;
  1156.     verts[1].uOverW = 0.0;
  1157.     verts[1].vOverW = 0.0;
  1158.         
  1159.     verts[2].x = windowWidth;
  1160.     verts[2].y = windowHeight;
  1161.     verts[2].z = inFrontZ;
  1162.     verts[2].invW = kWallsInvW_front;
  1163.     verts[2].uOverW = kFloor_U * verts[2].invW;
  1164.     verts[2].vOverW = 0.0;
  1165.         
  1166.     verts[3].x = wallWidth + inBackWidth;
  1167.     verts[3].y = floorDepth + inBackHeight;
  1168.     verts[3].z = inBackZ;
  1169.     verts[3].invW = kWallsInvW_back;
  1170.     verts[3].uOverW = kFloor_U * verts[3].invW;
  1171.     verts[3].vOverW = kFloor_V * verts[3].invW;
  1172.  
  1173.     GSTextureTriList_StoreQuad(
  1174.         &gTextureTriList, 
  1175.         &verts[0], 
  1176.         &verts[1], 
  1177.         &verts[2], 
  1178.         &verts[3], 
  1179.         gTriFlags,
  1180.         kTexture_floor);
  1181. }
  1182.  
  1183.  
  1184. // ===========================================================================
  1185. //    GSStoreRandomTris
  1186. // ===========================================================================
  1187.     void
  1188. GSStoreRandomTris()
  1189. {
  1190.     TQAVTexture                verts[3];
  1191.     short                    texture, i;
  1192.  
  1193.     for (i = 0; i < kBox1_triCount; i++) {
  1194.             // get a random vertex which is inside box1
  1195.         GSBoundedRandomVTexture(
  1196.                 &verts[0], kBox1_left, kBox1_right, kBox1_top, 
  1197.                 kBox1_bottom, kBox1_front, kBox1_back);
  1198.         GSBoundedRandomVTexture(
  1199.                 &verts[1], kBox1_left, kBox1_right, kBox1_top, 
  1200.                 kBox1_bottom, kBox1_front, kBox1_back);
  1201.         GSBoundedRandomVTexture(
  1202.                 &verts[2], kBox1_left, kBox1_right, kBox1_top, 
  1203.                 kBox1_bottom, kBox1_front, kBox1_back);
  1204.                 
  1205.             // use either the green or red lava textures.  this simply adds
  1206.             // 0 or 1 to kTexture_greenLava.  we subtract 0.01 just to make
  1207.             // sure we never get exactly 2.0.
  1208.         texture = kTexture_greenLava + (int) (GSRandomFloat() * 2.0 - 0.01);
  1209.         
  1210.         GSTextureTriList_StoreTri(
  1211.                 &gTextureTriList, &verts[0], &verts[1], &verts[2], gTriFlags, texture);
  1212.     } // endfor
  1213. }
  1214.  
  1215.  
  1216. // ===========================================================================
  1217. //    GSTextureTriList_New
  1218. // ===========================================================================
  1219.     Boolean 
  1220. GSTextureTriList_New(
  1221.     TGSTextureTriList*        inTextureTriList)
  1222. {
  1223.     GSAssert_(inTextureTriList);
  1224.     
  1225.         // we assume inTextureTriList doesn't already point to anything
  1226.     inTextureTriList->head = nil;
  1227.     inTextureTriList->tail = nil;
  1228.     inTextureTriList->triIndex = 0;
  1229.  
  1230.         // allocate a new TGSTextureTriGroup for the head of the list
  1231.     inTextureTriList->head = (TGSTextureTriGroup*) malloc(sizeof(TGSTextureTriGroup));
  1232.     inTextureTriList->tail = inTextureTriList->head;
  1233.     
  1234.     if (inTextureTriList->head == nil) {
  1235.             // we don't have enough memory to store a TGSTextureTriGroup,
  1236.             // so let the caller know.  the fact that we don't have enough
  1237.             // memory is indicated by the nil tail pointer.
  1238.         return false;
  1239.     }
  1240.     
  1241.     inTextureTriList->head->next = nil;
  1242.     
  1243.     return true;
  1244. }
  1245.  
  1246.  
  1247. // ===========================================================================
  1248. //    GSTextureTriList_Delete
  1249. // ===========================================================================
  1250.     void 
  1251. GSTextureTriList_Delete(
  1252.     TGSTextureTriList*        inTextureTriList)
  1253. {
  1254.     TGSTextureTriGroup*        currentGroup;
  1255.     TGSTextureTriGroup*        nextGroup;
  1256.     
  1257.     GSAssert_(inTextureTriList);
  1258.     
  1259.     for (currentGroup = inTextureTriList->head, nextGroup = nil; 
  1260.          currentGroup;
  1261.          currentGroup = nextGroup) {
  1262.              // save a pointer to the next group, before we free the current one
  1263.         nextGroup = currentGroup->next;
  1264.         
  1265.         free(currentGroup);
  1266.     } // endfor
  1267.     
  1268.     inTextureTriList->head = nil;
  1269.     inTextureTriList->tail = nil;
  1270.     inTextureTriList->triIndex = 0;
  1271. }
  1272.  
  1273.  
  1274. // ===========================================================================
  1275. //    GSTextureTriList_IsValid
  1276. // ===========================================================================
  1277.     Boolean 
  1278. GSTextureTriList_IsValid(
  1279.     TGSTextureTriList*        inTextureTriList)
  1280. {
  1281.     GSAssert_(inTextureTriList);
  1282.     
  1283.     return (inTextureTriList->tail != nil);
  1284. }
  1285.  
  1286.  
  1287. // ===========================================================================
  1288. //    GSTextureTriList_NewTextureTriGroup
  1289. // ===========================================================================
  1290.     Boolean 
  1291. GSTextureTriList_NewTextureTriGroup(
  1292.     TGSTextureTriList*        inTextureTriList)
  1293. {
  1294.     TGSTextureTriGroup*        newGroup = nil;
  1295.  
  1296.     GSAssert_(inTextureTriList);
  1297.     
  1298.     if (inTextureTriList->tail == nil) {
  1299.             // the tail should never be nil.  if it is, it means we were unable
  1300.             // to create a new TGSTextureTriGroup at some point.  so let the
  1301.             // caller know that.
  1302.         return false;
  1303.     }
  1304.     
  1305.     if (inTextureTriList->triIndex < kTextureTriGroupCount) {
  1306.             // we don't need a new TGSTextureTriGroup because the current
  1307.             // one isn't full yet
  1308.         return true;
  1309.     }
  1310.     
  1311.         // allocate a new TGSTextureTriGroup at the end of the list
  1312.     newGroup = (TGSTextureTriGroup*) malloc(sizeof(TGSTextureTriGroup));
  1313.     
  1314.     if (newGroup == nil) {
  1315.             // there's not enough memory to add a new group, so indicate that
  1316.             // in the list and let the caller know
  1317.         inTextureTriList->tail = nil;
  1318.         return false;
  1319.     }
  1320.     
  1321.         // attach the new group to the end of the list
  1322.     newGroup->next = nil;
  1323.     inTextureTriList->tail->next = newGroup;
  1324.     inTextureTriList->tail = newGroup;
  1325.         
  1326.         // reset the index
  1327.     inTextureTriList->triIndex = 0;
  1328.     
  1329.     return true;
  1330. }
  1331.  
  1332.  
  1333. // ===========================================================================
  1334. //    GSTextureTriList_StoreTri
  1335. // ===========================================================================
  1336.     Boolean 
  1337. GSTextureTriList_StoreTri(
  1338.     TGSTextureTriList*        inTextureTriList,
  1339.     TQAVTexture*            inVert1,
  1340.     TQAVTexture*            inVert2,
  1341.     TQAVTexture*            inVert3,
  1342.     unsigned long            inFlags,
  1343.     short                    inTexture)
  1344. {
  1345.     GSAssert_(inTextureTriList);
  1346.     GSAssert_(inVert1);
  1347.     GSAssert_(inVert2);
  1348.     GSAssert_(inVert3);
  1349.     
  1350.         // allocate a new TGSTextureTriGroup if necessary
  1351.     if (GSTextureTriList_NewTextureTriGroup(inTextureTriList) == false) {
  1352.             // there wasn't enough memory
  1353.         return false;
  1354.     }
  1355.     
  1356.         // copy the three vertices into the current TGSTextureTri
  1357.     inTextureTriList->tail->tris[inTextureTriList->triIndex].v1 = *inVert1;
  1358.     inTextureTriList->tail->tris[inTextureTriList->triIndex].v2 = *inVert2;
  1359.     inTextureTriList->tail->tris[inTextureTriList->triIndex].v3 = *inVert3;
  1360.  
  1361.         // copy the flags and texture index into the current TGSTextureTri
  1362.     inTextureTriList->tail->tris[inTextureTriList->triIndex].flags = inFlags;
  1363.     inTextureTriList->tail->tris[inTextureTriList->triIndex].texture = inTexture;
  1364.         
  1365.         // we just added a TGSTextureTri, so increment the index
  1366.     inTextureTriList->triIndex++;
  1367.         
  1368.     return true;
  1369. }
  1370.  
  1371.  
  1372. // ===========================================================================
  1373. //    GSTextureTriList_StoreQuad
  1374. // ===========================================================================
  1375.     Boolean 
  1376. GSTextureTriList_StoreQuad(
  1377.     TGSTextureTriList*        inTextureTriList,
  1378.     TQAVTexture*            inVert1,
  1379.     TQAVTexture*            inVert2,
  1380.     TQAVTexture*            inVert3,
  1381.     TQAVTexture*            inVert4,
  1382.     unsigned long            inFlags,
  1383.     short                    inTexture)
  1384. {
  1385.     Boolean result = false;
  1386.     
  1387.     GSAssert_(inTextureTriList);
  1388.     GSAssert_(inVert1);
  1389.     GSAssert_(inVert2);
  1390.     GSAssert_(inVert3);
  1391.     GSAssert_(inVert4);
  1392.  
  1393.         // first triangle
  1394.     result = GSTextureTriList_StoreTri(
  1395.         inTextureTriList,
  1396.         inVert1,
  1397.         inVert2,
  1398.         inVert3,
  1399.         inFlags,
  1400.         inTexture);
  1401.  
  1402.     if (result == false) {
  1403.         return result;
  1404.     }
  1405.     
  1406.         // second triangle
  1407.     result = GSTextureTriList_StoreTri(
  1408.         inTextureTriList,
  1409.         inVert1,
  1410.         inVert3,
  1411.         inVert4,
  1412.         inFlags,
  1413.         inTexture);
  1414.     
  1415.     return result;
  1416. }
  1417.  
  1418.  
  1419. // ===========================================================================
  1420. //    GSTextureTriList_Draw
  1421. // ===========================================================================
  1422.     void 
  1423. GSTextureTriList_Draw(
  1424.     TGSTextureTriList*        inTextureTriList,
  1425.     TGSDrawInfo*            inDrawInfo)
  1426. {
  1427.     TGSTextureTriGroup*        currentGroup;
  1428.     short                    maxTriIndex, i;
  1429.     
  1430.     GSAssert_(inTextureTriList);
  1431.     
  1432.     for (currentGroup = inTextureTriList->head; currentGroup;
  1433.             currentGroup = currentGroup->next) {
  1434.         if (currentGroup->next == nil) {
  1435.                 // we're on the last group.  the index of the last tri in
  1436.                 // this group is stored in inTextureTriList->triIndex
  1437.             maxTriIndex = inTextureTriList->triIndex;
  1438.         } else {
  1439.                 // the current group is full, so draw the full tri count
  1440.             maxTriIndex = kTextureTriGroupCount;
  1441.         }
  1442.         
  1443.         for (i = 0; i < maxTriIndex; i++) {
  1444.             GSAssert_(currentGroup->tris[i].texture < kTextureCount);
  1445.             
  1446.                 // set the left draw context's texture
  1447.             QASetPtr(inDrawInfo->mContext, kQATag_Texture, 
  1448.                     gTextures[currentGroup->tris[i].texture]);
  1449.  
  1450.             QADrawTriTexture(inDrawInfo->mContext, ¤tGroup->tris[i].v1,
  1451.                     ¤tGroup->tris[i].v2, ¤tGroup->tris[i].v3,
  1452.                     currentGroup->tris[i].flags);
  1453.         } // endfor
  1454.     } // endfor
  1455. }